package cn.tedu.charging.device.warm;

import cn.tedu.charging.common.pojo.po.ChargingStationPO;
import cn.tedu.charging.device.dao.repository.StationRepository;
import com.alibaba.nacos.common.utils.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.GeoOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@Slf4j
public class RedisWarmUp implements ApplicationRunner {
    //当前缓存 预热中考虑的应该业务流程,至于如何像redis调用api方法写入
    //应该由 架构师 高级工程师 负责封装工具类 CacheUtil
    @Autowired
    private StationRepository stationRepository;
    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.debug("即将执行缓存预热");
        //读取当前 charging_stations所有的站场信息 6个
        List<ChargingStationPO> pos=getAllStations();
        //在pos数据 非空的情况下 预热需要执行的
        if(CollectionUtils.isNotEmpty(pos)){
            log.debug("缓存源数据非空 预热缓存执行");
            saveStationCache(pos);
        }
    }

    private void saveStationCache(List<ChargingStationPO> pos) {
        //将pos每个po 取出 id作为 geo元素 绑定 po的坐标数据   redis数据类型geo类型
        //将pos每个po 使用id作为  key 存储每个po              redis的string类型
        for (ChargingStationPO po: pos){
            saveGeoCache(po);
            saveStringCache(po);
        }
        //调用pipeLine
        /**
         * 这段代码的API 大致意思 将for循环中包含的12个命令 在一次连接中完成
         * geoadd 6次
         * set 6次
         * 返回值results就是获取的每次执行的结果.
         * 命令执行的顺序 返回值的顺序
         */
        /*List results = redisTemplate.executePipelined((RedisCallback<?>) connection -> {
            //所有命令 set hset geoadd lpush zadd sadd全部放到这里
            for (ChargingStationPO po : pos) {
                saveGeoCache(po);
                saveStringCache(po);
                //读一个数据 将读的结果 return
            }
            return null;
        });*/
    }

    private void saveStringCache(ChargingStationPO po) {
        //set po.id() po
        //关于 与业务数据相关的key值的设计方式 一般会添加前后缀 绑定业务数据 可以使用_ 或者 :
        //TODO 前缀也应该使用常量
        String stationKey="station:cache:"+po.getId();//station:cache:1,2,3,4,5,6,7
        //考虑到序列化 默认redisTemplate 使用RedisSerializer.java() value值 元素值如果存储对象,类型
        //必须实现序列化接口
        redisTemplate.opsForValue().set(stationKey,po);
    }

    private void saveGeoCache(ChargingStationPO po) {
        //geoadd beijing_stations po.lon po.lat po.id
        GeoOperations geoOps = redisTemplate.opsForGeo();
        //TODO beijing_stations替换程常量
        geoOps.add("beijing_stations",new Point(po.getStationLng().doubleValue(),
                        po.getStationLat().doubleValue()), po.getId());
    }

    private List<ChargingStationPO> getAllStations() {
        return stationRepository.findAll();
    }
}
